package com.aegis.manage.service.gateway;

import cn.hutool.core.collection.CollectionUtil;
import com.aegis.common.utils.AssertUtil;
import com.aegis.manage.api.request.AddOrUpdateGatewayRouteRequest;
import com.aegis.manage.api.vo.RouteVO;
import com.aegis.manage.manager.AeNacosConfigManager;
import com.aegis.manage.utils.YamlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author wuweixin
 *
 * @Version 1.0
 * @Descritube
 */
@Slf4j
@Service
public class GatewayConfigServiceImpl implements GatewayConfigService {

    @Autowired
    private AeNacosConfigManager nacosConfigManager;

    private static final String DATA_ID = "gateway-routes.yaml";

    @Value("${spring.application.name}")
    private String artifactId;

    @Override
    public List<RouteVO> queryRouteList() {
        List<Map<String, Object>> routes = getRouteConfig();
        if (CollectionUtil.isEmpty(routes)) {
            return null;
        }
        List<RouteVO> result = new ArrayList<>();
        for (Map<String, Object> route : routes) {
            String id = (String) route.get("id");
            if (artifactId.equals(id)) {
                continue;
            }
            RouteVO routeVO = new RouteVO();
            routeVO.setId(id);
            routeVO.setUri((String) route.get("uri"));
            routeVO.setPredicates((List<String>) route.get("predicates"));
            if (CollectionUtil.isNotEmpty(routeVO.getPredicates())) {
                List<String> collect = routeVO.getPredicates().stream().filter(s ->
                        s.startsWith("Path")).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(collect)) {
                    routeVO.setPath(collect.get(0).replace("Path=", ""));
                }
            }
            result.add(routeVO);
        }
        return result;
    }

    @Override
    public void addRoute(AddOrUpdateGatewayRouteRequest request) {
        AssertUtil.operateFailed(artifactId.equals(request.getId()), "不合法的路由ID");
        String nacosConfig = nacosConfigManager.getNacosConfig(DATA_ID);
        Map<String, Object> configMap = YamlUtil.parseYamlToMap(nacosConfig);
        Map<String, Object> spring = (Map<String, Object>) configMap.get("spring");
        Map<String, Object> cloud = (Map<String, Object>) spring.get("cloud");
        Map<String, Object> gateway = (Map<String, Object>) cloud.get("gateway");
        // 获取现有的 routes 配置
        List<Map<String, Object>> routeConfig = (List<Map<String, Object>>) gateway.get("routes");
        for (Map<String, Object> routeMap : routeConfig) {
            AssertUtil.operateFailed(routeMap.get("id").equals(request.getId()), "路由ID已存在");
        }
        Map<String, Object> addRouteMap = new HashMap<>();
        addRouteMap.put("id", request.getId());
        addRouteMap.put("uri", request.getUri());
        addRouteMap.put("predicates", List.of("Path=" + request.getPath()));
        routeConfig.add(addRouteMap);
        String yaml = YamlUtil.convertMapToYaml(configMap);
        log.info("更新的yaml内容\n{}", yaml);
        AssertUtil.operateFailed(!nacosConfigManager.publishYamlConfig(DATA_ID, yaml), "添加失败");
    }

    @Override
    public void updateRoute(AddOrUpdateGatewayRouteRequest request) {
        AssertUtil.operateFailed(artifactId.equals(request.getId()), "不合法的路由ID");
        String nacosConfig = nacosConfigManager.getNacosConfig(DATA_ID);
        Map<String, Object> configMap = YamlUtil.parseYamlToMap(nacosConfig);
        Map<String, Object> spring = (Map<String, Object>) configMap.get("spring");
        Map<String, Object> cloud = (Map<String, Object>) spring.get("cloud");
        Map<String, Object> gateway = (Map<String, Object>) cloud.get("gateway");
        // 获取现有的 routes 配置
        List<Map<String, Object>> routeConfig = (List<Map<String, Object>>) gateway.get("routes");
        Map<String, Object> target = null;
        for (Map<String, Object> routeMap : routeConfig) {
            if (routeMap.get("id").equals(request.getId())) {
                target = routeMap;
                break;
            }
        }
        AssertUtil.operateFailed(target == null, "不存在的路由id");
        target.put("uri", request.getUri());
        target.put("predicates", List.of("Path=" + request.getPath()));
        String yaml = YamlUtil.convertMapToYaml(configMap);
        log.info("更新的yaml内容\n{}", yaml);
        AssertUtil.operateFailed(!nacosConfigManager.publishYamlConfig(DATA_ID, yaml), "更新失败");
    }

    @Override
    public void delRoute(String id) {
        AssertUtil.operateFailed(artifactId.equals(id), "不合法的路由ID");
        String nacosConfig = nacosConfigManager.getNacosConfig(DATA_ID);
        Map<String, Object> configMap = YamlUtil.parseYamlToMap(nacosConfig);
        Map<String, Object> spring = (Map<String, Object>) configMap.get("spring");
        Map<String, Object> cloud = (Map<String, Object>) spring.get("cloud");
        Map<String, Object> gateway = (Map<String, Object>) cloud.get("gateway");
        // 获取现有的 routes 配置
        List<Map<String, Object>> routeConfig = (List<Map<String, Object>>) gateway.get("routes");
        routeConfig.removeIf(routeMap -> routeMap.get("id").equals(id));
        String yaml = YamlUtil.convertMapToYaml(configMap);
        log.info("更新的yaml内容\n{}", yaml);
        AssertUtil.operateFailed(!nacosConfigManager.publishYamlConfig(DATA_ID, yaml), "更新失败");
    }


    private List<Map<String, Object>> getRouteConfig() {
        String nacosConfig = nacosConfigManager.getNacosConfig(DATA_ID);
        Map<String, Object> configMap = YamlUtil.parseYamlToMap(nacosConfig);
        Map<String, Object> spring = (Map<String, Object>) configMap.get("spring");
        Map<String, Object> cloud = (Map<String, Object>) spring.get("cloud");
        Map<String, Object> gateway = (Map<String, Object>) cloud.get("gateway");
        // 获取现有的 routes 配置
        return (List<Map<String, Object>>) gateway.get("routes");
    }

}
